package org.blame.lotterysystem.service.impl;

import cn.hutool.crypto.digest.DigestUtil;
import org.blame.lotterysystem.common.errorcode.ServiceErrorCodeConstants;
import org.blame.lotterysystem.common.exception.ServiceException;
import org.blame.lotterysystem.common.utils.JWTUtil;
import org.blame.lotterysystem.common.utils.RegexUtil;
import org.blame.lotterysystem.common.utils.SMSUtil;
import org.blame.lotterysystem.controller.param.ShortMessageParam;
import org.blame.lotterysystem.controller.param.UserLoginParam;
import org.blame.lotterysystem.controller.param.UserPasswordParam;
import org.blame.lotterysystem.controller.param.UserRegisterParam;
import org.blame.lotterysystem.dao.dataObject.Encrypt;
import org.blame.lotterysystem.dao.dataObject.UserDO;
import org.blame.lotterysystem.dao.mapper.UserMapper;
import org.blame.lotterysystem.service.UserService;
import org.blame.lotterysystem.service.VerificationCodeService;
import org.blame.lotterysystem.service.dto.UserInfoDTO;
import org.blame.lotterysystem.service.dto.UserLoginDTO;
import org.blame.lotterysystem.service.dto.UserRegisterDTO;
import org.blame.lotterysystem.service.enums.UserIdentityEnum;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;

@Service
public class UserServiceImpl implements UserService {

    @Autowired
    private UserMapper userMapper;

    @Autowired
    private VerificationCodeService verificationCodeService;
    private static final Logger logger= LoggerFactory.getLogger(UserServiceImpl.class);

    @Override
    public UserRegisterDTO register(UserRegisterParam param) {
        checkUserInfo(param);

//        进行用户的添加
        UserDO userDO=new UserDO();
        userDO.setUserName(param.getName());
        userDO.setEmail(param.getEmail());

        userDO.setPhoneNumber(new Encrypt(param.getPhoneNumber()));
        userDO.setIdentity(param.getIdentity());
        if(StringUtils.hasText(param.getPassword())){
            userDO.setPassword(DigestUtil.sha256Hex(param.getPassword()));
        }
//        存储数据
        userMapper.insert(userDO);

//        构造返回
        UserRegisterDTO userRegisterDTO=new UserRegisterDTO();
        userRegisterDTO.setUserId(userDO.getId());
        return userRegisterDTO;
    }

    @Override
    public UserLoginDTO login(UserLoginParam userLoginParam) {
        UserLoginDTO userLoginDTO;

        if(userLoginParam instanceof UserPasswordParam param){
            userLoginDTO=selectByPassword(param);

        }else if(userLoginParam instanceof ShortMessageParam param){
            userLoginDTO=selectByShortMessage(param);
        }else {
            throw new ServiceException(ServiceErrorCodeConstants.LOGIN_NOT_EXIST);
        }
        return userLoginDTO;
    }

    @Override
    public List<UserInfoDTO> findUserInfo(UserIdentityEnum identity) {
        String identityName=identity==null?null:identity.name();
        List<UserDO> userDOList=userMapper.selectUserInfoByIdentity(identityName);

        return userDOList.stream()
                .map(userDO ->{
                    UserInfoDTO userInfoDTO=new UserInfoDTO();
                    userInfoDTO.setUserId(userDO.getId());
                    userInfoDTO.setUserName(userDO.getUserName());
                    userInfoDTO.setEmail(userDO.getEmail());
                    userInfoDTO.setPhoneNumber(userDO.getPhoneNumber().getValue());
                    userInfoDTO.setIdentity(userDO.getIdentity());
                    return userInfoDTO;
                }).collect(Collectors.toList());
    }

    /**
     * 检查是否满足注册信息
     * @param param
     */
    @Override
    public void checkUserInfo(UserRegisterParam param) {
//        检查姓名
        if(param==null){
            throw new ServiceException(ServiceErrorCodeConstants.REGISTER_INFO_IS_EMPTY);
        }

//        检查邮箱格式
        if(!RegexUtil.checkMail(param.getEmail())){
            throw new ServiceException(ServiceErrorCodeConstants.MAIL_ERROR);
        }
//        检查手机号码格式
        if(!RegexUtil.checkMobile(param.getPhoneNumber())){
            throw new ServiceException(ServiceErrorCodeConstants.PHONE_NUMBER_ERROR);

        }
//        检查⾝份信息
        if(UserIdentityEnum.fromName(param.getIdentity())==null){
            throw new ServiceException(ServiceErrorCodeConstants.IDENTITY_ERROR);
        }
//        管理员必须设置密码
        if(UserIdentityEnum.fromName(param.getIdentity())==UserIdentityEnum.ADMIN && !StringUtils.hasText(param.getPassword())){
            throw new ServiceException(ServiceErrorCodeConstants.PASSWORD_IS_EMPTY);
        }
//        检查密码格式，最少六位
        if(RegexUtil.checkPassword(param.getPassword())){
            throw new ServiceException(ServiceErrorCodeConstants.PASSWORD_ERROR);
        }

        //      检查邮箱是否被使用
        if(checkEmailUsed(param.getEmail())){
            throw new ServiceException(ServiceErrorCodeConstants.MAIL_USED);
        }

//      检查手机号是否被使用
        if(checkPhoneUsed(param.getPhoneNumber())){
            throw new ServiceException(ServiceErrorCodeConstants.PHONE_NUMBER_USED);
        }


    }



    private UserLoginDTO selectByShortMessage(ShortMessageParam param) {

        if(!RegexUtil.checkMobile(param.getLoginMobile())){
            throw new ServiceException(ServiceErrorCodeConstants.PHONE_NUMBER_ERROR);
        }
        UserDO userDO=userMapper.selectPhoneNumber(new Encrypt(param.getLoginMobile()));
        if(userDO==null){
            throw new ServiceException(ServiceErrorCodeConstants.USER_INFO_IS_EMPTY);
        }else if(StringUtils.hasText(param.getMandatoryIdentity()) &&
                !param.getMandatoryIdentity()
                        .equalsIgnoreCase(userDO.getIdentity())){
            throw new ServiceException(ServiceErrorCodeConstants.IDENTITY_ERROR);
        }



        String code = verificationCodeService.getVerificationCode(param.getLoginMobile());
        if(code==null ||  !code.equals(param.getVerificationCode())){
            throw new ServiceException(ServiceErrorCodeConstants.VERIFICATION_CODE_ERROR);
        }
//      添加返回值
        Map<String,Object> claim=new HashMap<>();
        claim.put("id",userDO.getId());
        claim.put("identity",userDO.getIdentity());
        String token = JWTUtil.genJwt(claim);

        UserLoginDTO userLoginDTO=new UserLoginDTO();
        userLoginDTO.setToken(token);
        userLoginDTO.setIdentity(UserIdentityEnum.fromName(userDO.getIdentity()));
        return userLoginDTO;
    }

    private UserLoginDTO selectByPassword(UserPasswordParam param) {
        UserDO userDO;
//       判断手机登录还是邮箱登录
        if(RegexUtil.checkMobile(param.getLoginName())){
            userDO=userMapper.selectPhoneNumber(new Encrypt(param.getLoginName()));

        }else if(RegexUtil.checkMail(param.getLoginName())){
            userDO=userMapper.selectEmail(param.getLoginName());

        }else {
            throw new ServiceException(ServiceErrorCodeConstants.LOGIN_NOT_EXIST);
        }

//        校验登陆信息
        if(userDO==null){
            throw new ServiceException(ServiceErrorCodeConstants.USER_INFO_IS_EMPTY);
        } else if (StringUtils.hasText(param.getMandatoryIdentity())
                && !param.getMandatoryIdentity()
                .equalsIgnoreCase(userDO.getIdentity())) {
            throw new ServiceException(ServiceErrorCodeConstants.IDENTITY_ERROR);
        }else if (!DigestUtil.sha256Hex(param.getPassword()).equals(userDO.getPassword())){
            throw new ServiceException(ServiceErrorCodeConstants.PASSWORD_ERROR);
        }

//        添加返回值
        Map<String,Object> claim=new HashMap<>();
        claim.put("id",userDO.getId());
        claim.put("identity",userDO.getIdentity());

        String token = JWTUtil.genJwt(claim);

        UserLoginDTO userLoginDTO=new UserLoginDTO();
        userLoginDTO.setIdentity(UserIdentityEnum.fromName(userDO.getIdentity()));
        userLoginDTO.setToken(token);
        return userLoginDTO;
    }


    private boolean checkPhoneUsed(String phoneNumber) {
        int count=userMapper.countByPhone(new Encrypt(phoneNumber));
        return count>0;
    }

    private boolean checkEmailUsed(String email){
        int count=userMapper.countByMail(email);
        return count>0;
    }
}
